Créer un blog statique Hugo de A à Y

09/03/2018 - ~13mins www tuto hugo Dernière mise à jour le : 15/05/2019

Je vois que ces derniers temps Hugo commence à attirer de nouvelles personnes. Du coup, pourquoi pas vous proposer un article un peu plus en profondeur sur ce que j'ai compris d'Hugo. Je vous ai déjà fait un retour sur mon utilisation d'Hugo mais là ça va plus être sous le capot.

Je vais vous montrer comment faire ses premiers pas pour se monter un blog simple comme le mien avec un thème fait maison.

Facts

Tout d'abord voilà un ensemble de facts que j'ai accumulé.

Bon après ces quelques remarques globales, attaquons nous à la création d'un blog basique ainsi que son thème.

Créer la structure de votre site

Bon, sur votre machine personnelle, on va créer un dossier blog et maintenant tout se fera à partir de ce dossier. hugo new site ./ Et voilà votre dossier peuplé de nouveaux dossiers.

Créer un article

Afin de pouvoir expérimenter au plus vite, on va déjà créer un article bidon pour votre site.

Au préalable, on va créer une section blog : mkdir content/blog. Désormais tous vos articles de blog on les rangera dans ce dossier.

Créons l'article : hugo new blog/welcome.md . La chose à prendre en compte c'est que vous ne placez pas explicitement votre nouvel article dans content, il le fait de lui même. Quand vous utilisez la commande hugo new, ça sera automatiquement dans content.

Maintenant ajoutons du contenu à l'article : vim content/blog/welcome.md Et là vous devriez vous retrouver avec déjà quelques lignes dans votre article.

---

title: "Welcome"

date: 2018-03-07T12:15:24+01:00

draft: true

---

Ces données proviennent en fait du fichier archetypes/default.md fournit par défaut. Dans le jargon on appelle ça le frontmatter. Tout ce qui se trouve entre les --- (ou +++ en fonction du format). Donc par défaut le titre de votre article sera tiré du nom du fichier donné par la commande hugo new. La date correspondra à la création du fichier et par défaut votre fichier est à l'état de brouillon. Par défaut, Hugo ne génère pas les pages à l'état de brouillon. Pour la suite, mettez draft: false.

Vous pouvez rédiger en dessous votre article en utilisant la syntaxe MarkDown.

Bon après avoir ajouté un peu de contenu à cet article on va commencer les choses sérieuses : générer une page web !

Configuration

Donc pour générer votre site web, il vous suffit de taper : hugo

                    | EN

+-------------------+----+

  Pages             |  4

  Paginator pages   |  0

  Non-page files    |  0

  Static files      |  0

  Processed images  |  0

  Aliases           |  0

  Sitemaps          |  1

  Cleaned           |  0

Total in 21 ms

C'est tout de même mignon ce petit tableau récapitulatif ! Bon alors premièrement, votre site est probablement pas en anglais donc va falloir lui dire qu'il se goure.

Allez, voyons le config.toml

baseURL = "http://adresse.de.votre.site/"

languageCode = "fr-fr"

DefaultContentLanguage = "fr"

title = "le nom de votre site"

On pourra se contenter de ces réglages pour le moment. Et du coup si vous relancez la commande hugo vous verrez que vous générez désormais du français !

Paramètres fait maison

Hugo n'est pas chiant, vous pouvez rajouter des paramètres qui vous serviront pour votre thème, en plus des paramètres existants. Pour cela il suffit de faire ça sous la forme :

[params]

   mon_param_a_moi = "machin"

Vous pourrez les utiliser via .Site.params.mon_param_a_moi mais on verra ça mieux un peu plus loin.

Génération

Après avoir généré votre site, vous devriez voir un dossier public contenant quelques sous-dossiers et fichiers :

   public

   ├── blog

   │   └── index.xml

   ├── categories

   │   └── index.xml

   ├── index.xml

   ├── sitemap.xml

   └── tags

       └── index.xml

       3 directories, 5 files

La section blog a été créé avec dedans un index.xml, le dossier categories est automatiquement créé et contiendra les différentes catégories de vos articles de blog. sitemap.xml est le sitemap de votre site automatiquement généré par Hugo pour vous permettre d'être bien vu par les moteurs de recherche. tags est à l'image de categories et sera rempli tout seul au fur et à mesure. Tous les index.xml sont des flux RSS.

Mais du coup … je comprends pas … elles sont où les pages web ?

Pour l'instant vous n'avez pas donné d'instruction à Hugo sur la façon de générer les pages. Du coup en bon fainéant… il a rien foutu.

Layouts

Pour les moins anglophones, le layout est l'agencement des pages. En gros c'est le squelette HTML de vos pages que vous allez demander à Hugo de remplir avec le Markdown de vos articles.

On va commencer par le minimum absolu.

Dans layouts/index.html :

<html>

  <body>

    Yoplaboum !

  </body>

</html>

Je vous avais prévenu c'est vraiment peu. Maintenant on régénère via hugo et on voit qu'on a désormais public/index.html qui existe. Et comme par hasard il contient exactement la même chose que définie dans le layouts/index.html.

Ajoutons la magie d'Hugo : Toujours dans layouts/index.html :

<html>

  <body>

{{ range .Data.Pages }}

    <h1>{{ .Title }}</h1>

    {{ .Content }}

{{ end }}

  </bdy>

</html>

Et maintenant refaites un ptit coup de hugo et observez votre nouvel public/index.html

<html>

  <body>

    <h1>Welcome</h1>

    <p>coucou</p>

  </body>

</html>

Voilà, votre tout premier résultat tangible. Voyons ce qu'il s'est passé.

{{ range .Data.Pages }} indique à Hugo d'itérer sur toutes les pages de contenu que vous avez créé. Donc dans notre cas uniquement le fichier content/blog/welcome.md. Il s'agit d'une boucle qui s'exécutera pour chacun des items jusqu'à la fermeture qu'est {{ end }}.

Et dans cette boucle on récupère le {{ .Title }} qui est donc le title que vous avez mis dans le frontmatter de l'article. Et enfin {{ .Content }} est le rendu du MarkDown se trouvant hors du frontmatter de l'article.

C'est pas bien compliqué.

Partials

Hugo vous permet d'utiliser des morceaux de HTML que vous allez pouvoir inclure par la suite.

mkdir layouts/partials et ensuite éditons layouts/partials/header.html

<!DOCTYPE html>

<html lang='{{ .Site.Language.Lang }}'>

  <head>

    <title>{{ .Title }}</title>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">

    <meta name="description" content="{{ .Description }}">

    <meta name="keywords" content="{{ range .Params.Tags }}{{ . }},{{ end }}">

    <meta name="author" content="{{ .Params.author }}">

    {{ .Hugo.Generator }}

    <link rel="stylesheet" href="{{ .Site.BaseURL}}css/style.css">

    <link href="{{ .Site.RSSLink }}" rel="alternate" type="application/rss+xml" title="{{ .Site.Title }}">

    <link rel="icon" type="image/x-icon" href="{{ .Site.BaseURL }}favicon.ico">

  </head>

{{ .Site.Language.Lang }} sera remplacé par la langue de la page en question. Si vous avez la même page dans différentes langues cette variable sera ajustée en fonction.

{{ .HugoGenerator}} sera remplacé par la version de votre ptit Hugo.

Plusieurs fois vous trouverez {{ .Site.BaseURL }} c'est la variable définie dans config.toml à la racine de votre site.

Bref maintenant yapuka inclure ça dans votre layout : layouts/index.html en ajoutant juste

{{ partial "header.html" . }}

Un ptit coup de hugo et on observe le résultat. Le partial est inclus dans votre page web avec ses variables qui sont bien remplacées. Il nous reste encore un détail à voir et vous serez à même de vous débrouillez comme de grandes personnes.

List/Single pages

Hugo repose sur deux principaux types de pages. Les list pages et les single pages. Les single pages sont les pages affichant un item d'une section (dans notre cas un article de blog). Les list pages sont les pages listant les items d'une section (tous les articles du blog).

Jusqu'à présent, dans notre exemple, nous n'avons travaillé que la home page du site en bidouillant layouts/index.html. On va donc générer la page pour un article de blog.

mkdir layouts/blog puis éditons layouts/blog/single.html

{{ partial "header.html" . }}

<body>

  <header>

    <h1><a href="{{ .RelPermalink }}">{{ .Title }}</a><h1>

    <p class="meta">{{ .Date.Format "02/01/2006" }}</p>

  </header>

  <main>

    {{ .Content }}

  </main>

</body>

</html>

Bon ça reste assez simple (notez comme j'amène de nouveaux éléments que progressivement…). {{ .RelPermaLink }} est le lien vers l'article. {{ .Date.Format }} lit le paramètre date de l'article et le met au format "02/01/2006". J'avoue que cette désignation est assez étrange mais bon vous trouverez ici plus d'explication sur les formats possibles.

Impatients de voir le résultat ? hugo puis là vous aurez encore plus de fichiers \o/

public

├── blog

│   ├── index.xml

│   └── welcome

│       └── index.html

├── categories

│   └── index.xml

├── index.html

├── index.xml

├── sitemap.xml

└── tags

    └── index.xml

    4 directories, 7 files

Vous avez maintenant un dossier blog avec à l'intérieur un index.html qui se trouve être votre single page de l'article. Vous y trouverez comme prévu ce que vous avez mis dans layouts/blog/single.html.

Il ne reste donc plus qu'à faire la list page de la section blog :-)

layouts/blog/list.html

{{ partial "header.html" . }}

<body>

  <main>

  <h1>Mon blog moche</h1>

  {{ range .Data.Pages }}

    <header>

      <h2><a href="{{ .RelPermalink }}">{{ .Title }}</a></h2>

    </header>

    <article>

      {{ .Summary }}

    </article>

  {{ end}}

  </main>

</body>

</html>

Peu de nouveauté. {{ .Summary }} ne vous sortira pas l'article en entier mais juste le début. Une fois votre site généré vous aurez désormais un public/blog/index.html.

Petite pause dans l'apprentissage

Bon on a un truc qui marche pas trop mal. Plus qu'à raffiner.

Déjà pour se simplifier la vie, dans un autre terminal lancez hugo server --navigateToChanged -F -D. Cette commande lance le ptit serveur web interne d'Hugo en générant les article avec une date dans le futur (-F) et les articles en brouillons (-D). Une fois lancée, ils vous indiquera quelle adresse ouvrir dans votre navigateur (généralement http://localhost:1313). À chaque modification, vous serez redirigé vers la page éditée.

Encore pour se simplifier, on va améliorer archetypes/default.md pour y rajouter quelques infos intéressantes :

+++

Author = "Lord" (enfin si vous voulez m'attribuer tout votre mérite)

Description = ""

Categories = ["",""]

Tags = ["",""]

title = "{{ replace .Name "-" " " | title }}"

date = {{ .Date }}

draft = true

+++

Voilà, la description vous permettra de remplir la balise correspondante de la page, et Tags également ce qui améliorera sensiblement le SEO.

Bon on test ?

Créez un second article sur votre blog avec hugo new blog/le-second-article.md puis éditez-le pour y mettre un peu de contenu.

Si tout va bien, votre frontmatter (les métadonnées en haut du fichier contenant votre article) devrait être pré-rempli.

Peaufinnage

La page d'acceuil

Bon c'est pas mal mais du coup vous remarquerez qu'on a fait une connerie au début : quand on a commencé à faire le layout, on a fait layouts/index.html qui est votre homepage comme un sagouin.

Pour l'instant votre page d'accueil liste tous vos articles mais les affiche en entier ce qui est vite indigeste. Le plus simple est de juste copier layouts/blog/list.html et de le mettre à la place de layouts/index.html et ça sera plus cohérent.

Liens vers les articles suivant/précédent

C'est assez simple à ajouter automatiquement. On édite layouts/blog/single.html pour rajouter après l'article :

  <footer>

    {{ if .PrevInSection }}article précédent : <a href="{{ .PrevInSection.RelPermalink }}">{{ .PrevInSection.Title }}</a>{{ end }}

    {{ if .NextInSection }}article suivant : <a href="{{ .NextInSection.RelPermalink }}">{{ .NextInSection.Title }}</a>{{ end }}

  </footer>

Le if n'affichera que s'il existe un article précédent/suivant.

Un peu de style

Bon pour l'instant c'est pas super beau. Il va vous falloir dégainer votre plus joli CSS et le coller dans les ressources statiques. Donc mkdir static/css puis éditez static/css/style.css à votre convenance. Là c'est pour votre pomme.

Vous pouvez vous contenter de peu de règles écrites à la main plutôt que de forcément partir vers du Bootstrap.

Un flux RSS complet

Le template de génération de flux RSS par défaut ne place que le {{ .Summary }} d'un article. Pour le modifier il va falloir modifier le layout par défaut : mkdir layouts/_default/ et éditer layouts/_default/rss.xml

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">

  <channel>

    <title>{{ if eq  .Title  .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title>

    <link>{{ .Permalink }}</link>

    <description>Recent content {{ if ne  .Title  .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>

    <generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}

    <language>{{.}}</language>{{end}}{{ with .Site.Author.email }}

    <managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}

    <webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}

    <copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}

    <lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}

    {{ with .OutputFormats.Get "RSS" }}

        {{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}

    {{ end }}

    {{ range .Data.Pages }}

    <item>

      <title>{{ .Title }}</title>

      <link>{{ .Permalink }}</link>

      <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>

      {{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}

      <guid>{{ .Permalink }}</guid>

      <description>{{ .Content | html }}</description>

    </item>

    {{ end }}

  </channel>

</rss>

Faire un lien entre articles

C'est un peu une base du web de faire des liens entre les pages. Faire du web sans y coller des liens hypertexte est un non-sens. Bref. Pour pointer vers un autre article il suffit d'utiliser cette syntaxe :

[ceci est un lien]({{ < ref "/blog/welcome" > }})

Alors ?

Bha alors vous avez une base fonctionnelle pour un blog statique pondu par Hugo. C'était pas la mère à boire. Et normalement avec tout ça vous pouvez déjà pas mal vous en sortir. Une prochaine fois on verra comment héberger le bousin ;-)

En discuter sur le Journal du Hacker !

Lire du + récent : 8ème article d'avancement du Librem 5 + ancien : Les GLSA de chez Gentoo

Un article aléatoire : Fez

Similaire : Refonte complète du siteBonjour les visionnagesTrois astuces pour HugoMéta-actu du blogLes services du Fédiverse fin 2018